package com.zoro.barn.commons.db.autopage;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.zoro.barn.commons.foundation.web.ResponseInterface;
import com.zoro.barn.commons.tools.json.JsonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

/**
 * @author zhaoxingwu
 */
public class ResponsePageAdvice implements ResponseBodyAdvice<Object> {

    private final Logger logger = LoggerFactory.getLogger(getClass());
    private final Class<?> supportClass;
    private final String currentKey;
    private final String totalKey;

    public ResponsePageAdvice(String currentKey, String totalKey) {
        this(null, currentKey, totalKey);
    }

    public ResponsePageAdvice(Class<?> supportClass, String currentKey, String totalKey) {
        this.supportClass = supportClass;
        this.currentKey = currentKey;
        this.totalKey = totalKey;
    }

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        if (supportClass == null) {
            return true;
        }
        Class<?> rClass = returnType.getParameterType();
        if (rClass.isPrimitive() || Iterable.class.isAssignableFrom(rClass) || rClass.isArray()) {
            return false;
        }
        return supportClass.isAssignableFrom(returnType.getParameterType());
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        if (body == null) {
            return null;
        }
        boolean isDebugEnable = logger.isDebugEnabled();
        try {
            if (body instanceof ResponseInterface) {
                Object data = ((ResponseInterface<?>) body).getData();
                if (data instanceof PageList<?> list) {
                    ObjectNode result = JsonUtil.readJsonObject(JsonUtil.toString(body));
                    result.put(this.currentKey, list.getCurrent());
                    result.put(this.totalKey, list.getCount());
                    if (isDebugEnable) {
                        logger.debug("return type is PageList, current:{},count:{}", list.getCurrent(), list.getCount());
                    }
                    return result;
                }
            }
            if (isDebugEnable) {
                logger.debug("return type is not support to page");
            }
            return body;
        } catch (Exception e) {
            logger.error("can't parse response body to a json string, return original data", e);
            return body;
        }
    }
}
